use clap::{Parser, Subcommand};
use libiw_async::*;

#[derive(Parser)]
#[command(name = "iwtool")]
#[command(bin_name = "iwtool")]
enum IwtoolCli {
    /// 扫描AP
    Scan(ScanArgs),
    /// 配置网卡
    Set(SetArgs),
}

#[derive(clap::Args)]
#[command(version, about, long_about = None)]
struct ScanArgs {
    /// 搜索SSID关键词
    #[arg(short, long)]
    ssid: Option<String>,
}

#[derive(clap::Args)]
#[command(version, about)]
struct SetArgs {
    #[command(subcommand)]
    commands: SetCommand,
}

#[derive(Subcommand)]
enum SetCommand {
    Mode(ModeArgs),
    Channel(ChannelArgs),
    Freq(FreqArgs),
}

#[derive(clap::Args)]
struct ModeArgs {
    mode: Mode,
}

#[derive(clap::ValueEnum, Clone)]
enum Mode {
    Monitor,
    Managed,
}
#[derive(clap::Args)]
struct FreqArgs {
    freq: i32,
    width: Option<Width>,
}
#[derive(clap::Args)]
struct ChannelArgs {
    channel: i32,
    width: Option<Width>,
}
#[derive(Clone, clap::ValueEnum)]
enum Width {
    #[clap(name = "HT40+")]
    HT40a,
    #[clap(name = "HT40-")]
    HT40b,
    #[clap(name = "80MHz")]
    MHz80,
    #[clap(name = "160MHz")]
    MHz160,
}

#[tokio::main]
async fn main() {
    let cli = IwtoolCli::parse();

    let iw = IW::new().await.unwrap();

    let mut list = iw.interface_list().await.expect("无可用网卡");
    for card in &list {
        println!("ifname: {}", card);
    }

    let interface = list.remove(0);

    match cli {
        IwtoolCli::Scan(args) => {
            println!("scan ...");
            let mut ap_list = iw.scan(&interface).await.unwrap();
            if let Some(ssid) = args.ssid {
                ap_list.retain(|one| one.ssid.contains(&ssid));
            }
            for one in ap_list {
                println!("{}", one);
            }
        }
        IwtoolCli::Set(args) => match args.commands {
            SetCommand::Mode(a) => match a.mode {
                Mode::Monitor => iw
                    .set_mode(&interface, libiw_async::Mode::Monitor)
                    .await
                    .unwrap(),
                Mode::Managed => iw
                    .set_mode(&interface, libiw_async::Mode::Managed)
                    .await
                    .unwrap(),
            },
            SetCommand::Channel(args) => {
                let mut width = None;
                let mut second = None;
                if let Some(w) = args.width {
                    match w {
                        Width::HT40a => {
                            width = Some(BandWidth::HT40);
                            second = Some(SecondChannel::Above)
                        }
                        Width::HT40b => {
                            width = Some(BandWidth::HT40);
                            second = Some(SecondChannel::Below)
                        }
                        Width::MHz80 => width = Some(BandWidth::MHz80),
                        Width::MHz160 => width = Some(BandWidth::MHz160),
                    }
                }

                iw.set_channel(&interface, args.channel, width, second)
                    .await
                    .unwrap();
            }
            SetCommand::Freq(args) => {
                let mut width = None;
                let mut second = None;
                if let Some(w) = args.width {
                    match w {
                        Width::HT40a => {
                            width = Some(BandWidth::HT40);
                            second = Some(SecondChannel::Above)
                        }
                        Width::HT40b => {
                            width = Some(BandWidth::HT40);
                            second = Some(SecondChannel::Below)
                        }
                        Width::MHz80 => width = Some(BandWidth::MHz80),
                        Width::MHz160 => width = Some(BandWidth::MHz160),
                    }
                }

                iw.set_freq(&interface, args.freq, width, second)
                    .await
                    .unwrap();
            }
        },
    }
}
